<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AI志愿填报顾问</title>
    <link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
    <script src="https://cdn.jsdelivr.net/npm/vue@3.2.31/dist/vue.global.min.js"></script>
    <style>
        body {
            font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
        }

        /* 滚动条样式 */
        ::-webkit-scrollbar {
            width: 6px;
        }

        ::-webkit-scrollbar-track {
            background: #f1f1f1;
        }

        ::-webkit-scrollbar-thumb {
            background: #c1c1c1;
            border-radius: 3px;
        }

        ::-webkit-scrollbar-thumb:hover {
            background: #a8a8a8;
        }

        /* 输入框自适应高度 */
        textarea {
            min-height: 44px;
            max-height: 200px;
            transition: height 0.2s;
        }

        /* 加载动画 */
        @keyframes pulse {
            0%, 100% {
                opacity: 0.5;
            }
            50% {
                opacity: 1;
            }
        }

        .animate-pulse {
            animation: pulse 1.5s infinite;
        }

        .delay-100 {
            animation-delay: 0.1s;
        }

        .delay-200 {
            animation-delay: 0.2s;
        }

        /* 打字机效果 */
        .typing-cursor::after {
            content: "|";
            animation: blink 1s step-end infinite;
        }

        @keyframes blink {
            from, to {
                opacity: 1;
            }
            50% {
                opacity: 0;
            }
        }

        /* 角色列表项悬停效果 */
        .character-item:hover {
            background-color: #e5e7eb;
        }

        .dark .character-item:hover {
            background-color: #4b5563;
        }

        /* 选中的角色项 */
        .character-item.active {
            background-color: #3b82f6;
            color: white;
        }

        .dark .character-item.active {
            background-color: #3b82f6;
        }

        /* 切换按钮样式 */
        .toggle-btn {
            position: absolute;
            top: 50%;
            transform: translateY(-50%);
            z-index: 10;
            background-color: #3b82f6;
            color: white;
            border: none;
            border-radius: 0 4px 4px 0;
            width: 24px;
            height: 40px;
            cursor: pointer;
            box-shadow: 2px 0 4px rgba(0, 0, 0, 0.1);
        }

        .dark .toggle-btn {
            box-shadow: 2px 0 4px rgba(0, 0, 0, 0.3);
        }

        /* 弹窗样式 */
        .modal-overlay {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-color: rgba(0, 0, 0, 0.5);
            display: flex;
            align-items: center;
            justify-content: center;
            z-index: 1000;
        }

        .modal-content {
            background-color: white;
            border-radius: 8px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
            width: 90%;
            max-width: 500px;
            max-height: 90vh;
            overflow-y: auto;
        }

        .dark .modal-content {
            background-color: #1f2937;
        }

        .modal-header {
            padding: 1rem 1.5rem;
            border-bottom: 1px solid #e5e7eb;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .dark .modal-header {
            border-bottom: 1px solid #374151;
        }

        .modal-body {
            padding: 1.5rem;
        }

        .modal-footer {
            padding: 1rem 1.5rem;
            border-top: 1px solid #e5e7eb;
            display: flex;
            justify-content: flex-end;
            gap: 0.5rem;
        }

        .dark .modal-footer {
            border-top: 1px solid #374151;
        }

        .form-group {
            margin-bottom: 1rem;
        }

        .form-label {
            display: block;
            margin-bottom: 0.5rem;
            font-weight: 500;
        }

        .dark .form-label {
            color: #f9fafb;
        }

        .form-input, .form-textarea {
            width: 100%;
            padding: 0.5rem;
            border: 1px solid #d1d5db;
            border-radius: 4px;
        }

        .dark .form-input, .dark .form-textarea {
            background-color: #111827;
            border: 1px solid #374151;
            color: #f9fafb;
        }

        .btn {
            padding: 0.5rem 1rem;
            border-radius: 4px;
            cursor: pointer;
            font-weight: 500;
        }

        .btn-primary {
            background-color: #3b82f6;
            color: white;
        }

        .btn-primary:hover {
            background-color: #2563eb;
        }

        .btn-secondary {
            background-color: #6b7280;
            color: white;
        }

        .btn-secondary:hover {
            background-color: #4b5563;
        }

        .btn-danger {
            background-color: #ef4444;
            color: white;
        }

        .btn-danger:hover {
            background-color: #dc2626;
        }

        .character-item {
            position: relative;
        }

        .character-actions {
            display: flex;
            gap: 0.5rem;
            position: absolute;
            right: 12px;
            top: 50%;
            transform: translateY(-50%);
            opacity: 0;
            transition: opacity 0.2s ease;
        }

        .character-item:hover .character-actions {
            opacity: 1;
        }

        .action-btn {
            padding: 0.25rem 0.5rem;
            border-radius: 4px;
            cursor: pointer;
            font-size: 0.875rem;
        }

        .edit-btn {
            background-color: #f3f4f6;
            color: #374151;
        }

        .dark .edit-btn {
            background-color: #374151;
            color: #f9fafb;
        }

        .delete-btn {
            background-color: #fee2e2;
            color: #dc2626;
        }

        .dark .delete-btn {
            background-color: #7f1d1d;
            color: #fecaca;
        }
    </style>
</head>
<body>
<div id="app" class="flex flex-col h-screen bg-gray-50">
    <!-- 顶部导航栏 -->
    <header class="bg-white shadow-sm py-3 px-4 flex items-center justify-between">
        <div class="flex items-center">
            <div class="text-xl font-bold text-blue-600">AI志愿填报顾问</div>
        </div>
        <div class="flex items-center space-x-3">
            <button
                    @click="startNewConversation"
                    class="ml-2 p-3 rounded-lg bg-green-500 hover:bg-green-600 text-white" style="width: 50px">
                <i class="fas fa-plus"></i>
            </button>
            <button @click="toggleDarkMode" class="p-2 rounded-full hover:bg-gray-100">
                <i :class="darkMode ? 'fas fa-moon text-gray-600' : 'fas fa-sun text-gray-600'"></i>
            </button>
        </div>
    </header>

    <!-- 主内容区域 - 左右布局 -->
    <div class="flex flex-1 overflow-hidden">
        <!-- 左侧角色列表 (20%宽度) -->
        <div v-if="showCharacterList" :class="['relative', darkMode ? 'bg-gray-800 border-gray-700' : 'bg-white border-gray-200']">
            <div class="w-64 border-r p-4 flex flex-col h-full">
                <h2 :class="['text-lg font-bold mb-4', darkMode ? 'text-white' : 'text-gray-800']">角色列表</h2>
                
                <!-- 角色列表 -->
                <div class="flex-1 overflow-y-auto mb-4">
                    <div 
                        v-for="character in characters" 
                        :key="character.id"
                        @click="selectCharacter(character)"
                        :class="[
                            'character-item p-3 rounded-lg cursor-pointer mb-2 transition-colors',
                            darkMode ? 'text-white' : 'text-gray-800',
                            selectedCharacter && selectedCharacter.id === character.id ? 'active' : ''
                        ]"
                    >
                        <div>{{ character.name }}</div>
                        <div class="character-actions">
                            <button @click.stop="editCharacter(character)" class="action-btn edit-btn">
                                <i class="fas fa-edit"></i>
                            </button>
                            <button @click.stop="deleteCharacter(character.id)" class="action-btn delete-btn">
                                <i class="fas fa-trash"></i>
                            </button>
                        </div>
                    </div>
                </div>
                
                <!-- 添加角色按钮 -->
                <div class="mt-auto">
                    <button 
                        @click="openAddCharacterModal"
                        :class="['w-full py-2 rounded', darkMode ? 'bg-blue-600 hover:bg-blue-700' : 'bg-blue-500 hover:bg-blue-600 text-white']"
                    >
                        <i class="fas fa-plus mr-2"></i>添加角色
                    </button>
                </div>
            </div>
        </div>

        <!-- 切换按钮 -->
        <button 
            @click="toggleCharacterList"
            class="toggle-btn"
            :style="{ left: showCharacterList ? '256px' : '0' }"
            :title="showCharacterList ? '隐藏角色列表' : '显示角色列表'"
        >
            <i :class="showCharacterList ? 'fas fa-chevron-left' : 'fas fa-chevron-right'"></i>
        </button>

        <!-- 右侧对话窗口 -->
        <div :class="['flex-1 flex flex-col', showCharacterList ? 'w-4/5' : 'w-full']">
            <!-- 聊天内容区域 -->
            <main class="flex-1 overflow-y-auto p-4 space-y-6" ref="chatContainer" :class="{ 'bg-gray-800': darkMode }">
                <div v-for="(message, index) in messages" :key="index" class="max-w-3xl mx-auto">
                    <div :class="['flex', message.role === 'user' ? 'justify-end' : 'justify-start']">
                        <div :class="['flex items-start space-x-3', message.role === 'user' ? 'flex-row-reverse space-x-reverse' : '']">
                            <div :class="['w-8 h-8 rounded-full flex items-center justify-center',
                                            message.role === 'user' ? 'bg-blue-100 text-blue-600' : 'bg-green-100 text-green-600',
                                            darkMode && message.role === 'assistant' ? 'bg-gray-700 text-green-400' : '']">
                                <i :class="message.role === 'user' ? 'fas fa-user' : 'fas fa-robot'"></i>
                            </div>
                            <div :class="['p-3 rounded-lg max-w-lg',
                                            message.role === 'user'
                                                ? 'bg-blue-500 text-white'
                                                : darkMode
                                                    ? 'bg-gray-700 text-gray-100 border-gray-600'
                                                    : 'bg-white shadow border border-gray-100']">
                                <div v-if="message.role === 'assistant' && message.isLoading" class="flex space-x-2">
                                    <div :class="['w-2 h-2 rounded-full', darkMode ? 'bg-gray-400' : 'bg-gray-300', 'animate-pulse']"></div>
                                    <div :class="['w-2 h-2 rounded-full', darkMode ? 'bg-gray-400' : 'bg-gray-300', 'animate-pulse delay-100']"></div>
                                    <div :class="['w-2 h-2 rounded-full', darkMode ? 'bg-gray-400' : 'bg-gray-300', 'animate-pulse delay-200']"></div>
                                </div>
                                <div v-else class="whitespace-pre-wrap">
                                        <span v-for="(char, charIndex) in message.content" :key="charIndex"
                                              :class="{'opacity-0': charIndex >= message.visibleChars, 'fade-in': charIndex < message.visibleChars}">
                                            {{ char }}
                                        </span>
                                    <span v-if="message.isStreaming" class="typing-cursor"></span>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </main>

            <!-- 输入框区域 -->
            <footer :class="['border-t p-4', darkMode ? 'bg-gray-800 border-gray-700' : 'bg-white border-gray-200']">
                <div class="max-w-3xl mx-auto relative">
                    <div class="flex items-center">
                            <textarea
                                    v-model="userInput"
                                    @keydown.enter.exact.prevent="sendMessage"
                                    @keydown.ctrl.enter.exact.prevent="sendMessage"
                                    @keydown.esc.exact="stopResponse"
                                    placeholder="输入您的问题..."
                                    :class="['flex-1 border rounded-lg py-3 px-4 pr-12 focus:outline-none focus:ring-2 resize-none',
                                        darkMode
                                            ? 'bg-gray-700 border-gray-600 text-white focus:ring-blue-400 placeholder-gray-400'
                                            : 'border-gray-300 focus:ring-blue-500 focus:border-transparent']"
                                    rows="1"
                                    ref="textarea"
                                    @input="adjustTextareaHeight"
                            ></textarea>
                        <!-- 新建会话按钮 -->

                        <button
                                @click="isLoading ? stopResponse() : sendMessage()"
                                :disabled="!userInput.trim() && !isLoading"
                                :class="['ml-2 p-3 rounded-lg',
                                        isLoading
                                            ? 'bg-red-500 hover:bg-red-600 text-white'
                                            : 'bg-blue-500 hover:bg-blue-600 text-white',
                                        'disabled:opacity-50 disabled:cursor-not-allowed']"
                        >
                            <i :class="isLoading ? 'fas fa-stop' : 'fas fa-paper-plane'"></i>
                        </button>
                    </div>
                </div>
            </footer>
        </div>
    </div>

    <!-- 添加角色弹窗 -->
    <div v-if="showAddCharacterModal" class="modal-overlay">
        <div class="modal-content">
            <div :class="['modal-header', darkMode ? 'bg-gray-700' : 'bg-gray-50']">
                <h3 class="text-lg font-medium">添加角色</h3>
                <button @click="closeAddCharacterModal" class="text-gray-500 hover:text-gray-700">
                    <i class="fas fa-times"></i>
                </button>
            </div>
            <div class="modal-body">
                <div class="form-group">
                    <label :class="['form-label', darkMode ? 'text-white' : 'text-gray-700']">角色名称</label>
                    <input 
                        v-model="newCharacter.name" 
                        type="text" 
                        :class="['form-input', darkMode ? 'bg-gray-600 border-gray-500' : '']"
                        placeholder="请输入角色名称"
                    >
                </div>
                <div class="form-group">
                    <label :class="['form-label', darkMode ? 'text-white' : 'text-gray-700']">角色人设</label>
                    <textarea 
                        v-model="newCharacter.persona" 
                        rows="5" 
                        :class="['form-textarea', darkMode ? 'bg-gray-600 border-gray-500' : '']"
                        placeholder="请输入角色人设信息"
                    ></textarea>
                </div>
            </div>
            <div class="modal-footer">
                <button @click="closeAddCharacterModal" :class="['btn btn-secondary', darkMode ? 'bg-gray-600 hover:bg-gray-700' : '']">取消</button>
                <button @click="addCharacter" :class="['btn btn-primary', darkMode ? 'bg-blue-600 hover:bg-blue-700' : '']">添加</button>
            </div>
        </div>
    </div>

    <!-- 编辑角色弹窗 -->
    <div v-if="showEditCharacterModal" class="modal-overlay">
        <div class="modal-content">
            <div :class="['modal-header', darkMode ? 'bg-gray-700' : 'bg-gray-50']">
                <h3 class="text-lg font-medium">编辑角色</h3>
                <button @click="closeEditCharacterModal" class="text-gray-500 hover:text-gray-700">
                    <i class="fas fa-times"></i>
                </button>
            </div>
            <div class="modal-body">
                <div class="form-group">
                    <label :class="['form-label', darkMode ? 'text-white' : 'text-gray-700']">角色名称</label>
                    <input 
                        v-model="editingCharacter.name" 
                        type="text" 
                        :class="['form-input', darkMode ? 'bg-gray-600 border-gray-500' : '']"
                        placeholder="请输入角色名称"
                    >
                </div>
                <div class="form-group">
                    <label :class="['form-label', darkMode ? 'text-white' : 'text-gray-700']">角色人设</label>
                    <textarea 
                        v-model="editingCharacter.persona" 
                        rows="5" 
                        :class="['form-textarea', darkMode ? 'bg-gray-600 border-gray-500' : '']"
                        placeholder="请输入角色人设信息"
                    ></textarea>
                </div>
            </div>
            <div class="modal-footer">
                <button @click="closeEditCharacterModal" :class="['btn btn-secondary', darkMode ? 'bg-gray-600 hover:bg-gray-700' : '']">取消</button>
                <button @click="updateCharacter" :class="['btn btn-primary', darkMode ? 'bg-blue-600 hover:bg-blue-700' : '']">保存</button>
            </div>
        </div>
    </div>
</div>

<script>
    const {createApp, ref, nextTick, onMounted, watch} = Vue;

    createApp({
        setup() {
            const messages = ref([]);
            const userInput = ref('');
            const isLoading = ref(false);
            const chatContainer = ref(null);
            const textarea = ref(null);
            const darkMode = ref(false);
            
            // 角色相关数据
            const characters = ref([]);
            const selectedCharacter = ref(null);
            const showCharacterList = ref(true); // 控制角色列表显示/隐藏
            
            // 弹窗相关
            const showAddCharacterModal = ref(false);
            const showEditCharacterModal = ref(false);
            const newCharacter = ref({ name: '', persona: '' });
            const editingCharacter = ref({ id: null, name: '', persona: '' });

            const memoeryId = ref(Date.now().toString());
            let controller = null;
            let typingInterval = null;
            let currentTypingIndex = 0;

            // 获取所有角色
            const fetchCharacters = async () => {
                try {
                    const response = await fetch('/api/roles');
                    if (response.ok) {
                        characters.value = await response.json();
                        // 默认选择第一个角色
                        if (characters.value.length > 0 && !selectedCharacter.value) {
                            selectedCharacter.value = characters.value[0];
                            // 更新欢迎消息以包含角色名称
                            updateWelcomeMessage();
                        }
                    }
                } catch (error) {
                    console.error('获取角色列表失败:', error);
                }
            };

            // 更新欢迎消息
            const updateWelcomeMessage = () => {
                const roleName = selectedCharacter.value ? selectedCharacter.value.name : '顾问';
                if (messages.value.length > 0 && messages.value[0].role === 'assistant') {
                    messages.value[0].content = `你好！我是传智教育提供的AI志愿填报${roleName}，请问有什么能帮到您？`;
                    messages.value[0].visibleChars = messages.value[0].content.length;
                    scrollToBottom();
                }
            };

            // 切换角色列表显示/隐藏
            const toggleCharacterList = () => {
                showCharacterList.value = !showCharacterList.value;
            };

            // 打开添加角色弹窗
            const openAddCharacterModal = () => {
                newCharacter.value = { name: '', persona: '' };
                showAddCharacterModal.value = true;
            };

            // 关闭添加角色弹窗
            const closeAddCharacterModal = () => {
                showAddCharacterModal.value = false;
            };

            // 添加角色
            const addCharacter = async () => {
                if (newCharacter.value.name.trim() !== '') {
                    try {
                        const response = await fetch('/api/roles', {
                            method: 'POST',
                            headers: {
                                'Content-Type': 'application/json'
                            },
                            body: JSON.stringify({
                                name: newCharacter.value.name.trim(),
                                persona: newCharacter.value.persona.trim()
                            })
                        });
                        
                        if (response.ok) {
                            closeAddCharacterModal();
                            await fetchCharacters(); // 重新加载角色列表
                        }
                    } catch (error) {
                        console.error('添加角色失败:', error);
                    }
                }
            };

            // 打开编辑角色弹窗
            const editCharacter = (character) => {
                editingCharacter.value = { 
                    id: character.id, 
                    name: character.name, 
                    persona: character.persona || '' 
                };
                showEditCharacterModal.value = true;
            };

            // 关闭编辑角色弹窗
            const closeEditCharacterModal = () => {
                showEditCharacterModal.value = false;
            };

            // 更新角色
            const updateCharacter = async () => {
                if (editingCharacter.value.name.trim() !== '') {
                    try {
                        const response = await fetch(`/api/roles/${editingCharacter.value.id}`, {
                            method: 'PUT',
                            headers: {
                                'Content-Type': 'application/json'
                            },
                            body: JSON.stringify({
                                name: editingCharacter.value.name.trim(),
                                persona: editingCharacter.value.persona.trim()
                            })
                        });
                        
                        if (response.ok) {
                            closeEditCharacterModal();
                            await fetchCharacters(); // 重新加载角色列表
                        }
                    } catch (error) {
                        console.error('更新角色失败:', error);
                    }
                }
            };

            // 删除角色
            const deleteCharacter = async (id) => {
                if (characters.value.length <= 1) {
                    alert('至少需要保留一个角色');
                    return;
                }
                
                if (confirm('确定要删除这个角色吗？')) {
                    try {
                        const response = await fetch(`/api/roles/${id}`, {
                            method: 'DELETE'
                        });
                        
                        if (response.ok) {
                            await fetchCharacters(); // 重新加载角色列表
                        }
                    } catch (error) {
                        console.error('删除角色失败:', error);
                    }
                }
            };

            // 选择角色
            const selectCharacter = (character) => {
                selectedCharacter.value = character;
                updateWelcomeMessage();
            };

            // 调整文本区域高度
            const adjustTextareaHeight = () => {
                const textareaEl = textarea.value;
                textareaEl.style.height = 'auto';
                textareaEl.style.height = `${Math.min(textareaEl.scrollHeight, 200)}px`;
            };

            // 滚动到底部
            const scrollToBottom = () => {
                nextTick(() => {
                    if (chatContainer.value) {
                        chatContainer.value.scrollTop = chatContainer.value.scrollHeight;
                    }
                });
            };

            // 切换暗黑模式
            const toggleDarkMode = () => {
                darkMode.value = !darkMode.value;
                localStorage.setItem('darkMode', darkMode.value);
            };

            // 新建会话
            const startNewConversation = () => {
                // 清空聊天记录
                messages.value = [];
                // 生成新的 memoryId
                memoeryId.value = Date.now().toString();
                // 添加欢迎消息
                const roleName = selectedCharacter.value ? selectedCharacter.value.name : '顾问';
                messages.value.push({
                    role: 'assistant',
                    content: `你好！我是传智教育提供的AI志愿填报${roleName}，请问有什么能帮到您？`,
                    isLoading: false,
                    visibleChars: 0,
                    isStreaming: false
                });
                // 确保欢迎消息完全可见
                messages.value[0].visibleChars = messages.value[0].content.length;
                // 滚动到底部
                scrollToBottom();
                // 聚焦输入框
                nextTick(() => {
                    textarea.value.focus();
                });
            };

            // 模拟逐字打印效果
            const startTypingEffect = (messageIndex) => {
                const message = messages.value[messageIndex];
                if (!message || message.visibleChars >= message.content.length) {
                    clearInterval(typingInterval);
                    typingInterval = null;
                    messages.value[messageIndex].isStreaming = false;
                    return;
                }

                messages.value[messageIndex].visibleChars++;
                scrollToBottom();
            };

            // 发送消息
            const sendMessage = async () => {
                if (!userInput.value.trim() || isLoading.value) return;

                // 中止之前的请求
                if (controller) {
                    controller.abort();
                }
                controller = new AbortController();

                const userMessage = {
                    role: 'user',
                    content: userInput.value.trim(),
                    isLoading: false,
                    visibleChars: userInput.value.trim().length,
                    isStreaming: false
                };

                messages.value.push(userMessage);

                const assistantMessage = {
                    role: 'assistant',
                    content: '',
                    isLoading: true,
                    visibleChars: 0,
                    isStreaming: true
                };

                messages.value.push(assistantMessage);

                userInput.value = '';
                adjustTextareaHeight();
                scrollToBottom();

                isLoading.value = true;

                try {
                    // 在请求中包含选中的角色人设信息和角色ID
                    const roleId = selectedCharacter.value ? selectedCharacter.value.id : null;
                    const messageWithPersona = `${selectedCharacter.value.persona || ''}\n\n用户问题: ${userMessage.content}`;
                    
                    const response = await fetch(`/stream/chat?message=${encodeURIComponent(messageWithPersona)}&memoryId=${memoeryId.value}&roleId=${roleId}`, {
                        signal: controller.signal
                    });

                    if (!response.ok) {
                        throw new Error(`HTTP error! status: ${response.status}`);
                    }

                    const reader = response.body.getReader();
                    const decoder = new TextDecoder('utf-8');
                    let buffer = '';
                    let messageIndex = messages.value.length - 1;

                    // 先清除之前的打字效果
                    if (typingInterval) {
                        clearInterval(typingInterval);
                        typingInterval = null;
                    }

                    // 开始流式处理
                    while (true) {
                        const {done, value} = await reader.read();
                        if (done) break;

                        const chunk = decoder.decode(value, {stream: true});
                        buffer += chunk;

                        // 直接更新内容
                        messages.value[messageIndex].content = buffer;
                        messages.value[messageIndex].isLoading = false;

                        // 启动打字效果
                        if (!typingInterval) {
                            typingInterval = setInterval(() => {
                                startTypingEffect(messageIndex);
                            }, 20); // 调整这个值可以改变打字速度
                        }

                        scrollToBottom();
                    }

                } catch (error) {
                    if (error.name === 'AbortError') {
                        console.log('请求被用户中止');
                    } else {
                        console.error('请求出错:', error);
                        const lastMessage = messages.value[messages.value.length - 1];
                        lastMessage.content = '抱歉，请求过程中出现错误: ' + error.message;
                        lastMessage.visibleChars = lastMessage.content.length;
                    }
                } finally {
                    const lastMessage = messages.value[messages.value.length - 1];
                    lastMessage.isLoading = false;
                    lastMessage.isStreaming = false;

                    // 确保所有字符都可见
                    if (lastMessage.visibleChars < lastMessage.content.length) {
                        lastMessage.visibleChars = lastMessage.content.length;
                    }

                    isLoading.value = false;
                    controller = null;

                    if (typingInterval) {
                        clearInterval(typingInterval);
                        typingInterval = null;
                    }

                    scrollToBottom();
                }
            };

            // 停止响应
            const stopResponse = () => {
                if (controller) {
                    controller.abort();
                    const lastMessage = messages.value[messages.value.length - 1];
                    lastMessage.isLoading = false;
                    lastMessage.isStreaming = false;

                    if (lastMessage.visibleChars < lastMessage.content.length) {
                        lastMessage.visibleChars = lastMessage.content.length;
                    }

                    isLoading.value = false;
                    controller = null;

                    if (typingInterval) {
                        clearInterval(typingInterval);
                        typingInterval = null;
                    }
                }
            };

            // 初始化
            onMounted(() => {
                // 检查暗黑模式偏好
                darkMode.value = localStorage.getItem('darkMode') === 'true' ||
                    (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches);

                // 获取角色列表
                fetchCharacters();

                // 添加欢迎消息
                messages.value.push({
                    role: 'assistant',
                    content: '你好！我是传智教育提供的AI志愿填报顾问，请问有什么能帮到您？',
                    isLoading: false,
                    visibleChars: 0,
                    isStreaming: false
                });

                // 确保欢迎消息完全可见
                messages.value[0].visibleChars = messages.value[0].content.length;
                scrollToBottom();

                // 聚焦输入框
                nextTick(() => {
                    textarea.value.focus();
                });
            });

            // 监听消息变化自动滚动
            watch(messages, scrollToBottom, {deep: true});

            return {
                messages,
                userInput,
                isLoading,
                darkMode,
                chatContainer,
                textarea,
                sendMessage,
                stopResponse,
                toggleDarkMode,
                adjustTextareaHeight,
                startNewConversation,
                // 角色相关
                characters,
                selectedCharacter,
                showCharacterList,
                selectCharacter,
                toggleCharacterList,
                // 弹窗相关
                showAddCharacterModal,
                showEditCharacterModal,
                newCharacter,
                editingCharacter,
                openAddCharacterModal,
                closeAddCharacterModal,
                addCharacter,
                editCharacter,
                closeEditCharacterModal,
                updateCharacter,
                deleteCharacter
            };
        }
    }).mount('#app');
</script>
</body>
</html>